package com.one.group.user.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.one.group.enums.ResultEnum;
import com.one.group.exception.BusinessException;
import com.one.group.model.dto.SpHouseRentalAddDto;
import com.one.group.model.dto.SpHouseRentalQueryDto;
import com.one.group.model.entity.*;
import com.one.group.model.vo.SpHouseRentalListVo;
import com.one.group.model.vo.SpHouseVo;
import com.one.group.service.*;
import com.one.group.user.service.HouseCacheService;
import com.one.group.user.tool.TenantTool;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class HouseCacheServiceImpl implements HouseCacheService {
    @Autowired
    private RedisTemplate redisTemplate;
    @DubboReference
    private SpBuildingtypeService spBuildingtypeService;
    @DubboReference
    private SpBuildingService spBuildingService;
    @DubboReference
    private SpUnitService spUnitService;
    @DubboReference
    private SpHouseService spHouseService;
    @Autowired
    private TenantTool tenantTool;
    //配置缓存key的前缀
    public static final String CACHE_KEY_PREFIX_TYPE = "cache:buildingType:";
    //配置缓存key的前缀
    public static final String CACHE_KEY_PREFIX = "cache:buildingList:";
    //配置缓存key的前缀
    public static final String CACHE_KEY_PREFIX_UNIT = "cache:unitList:";
    public static final String CACHE_KEY_PREFIX_HOUSE = "cache:houseList:";
    public static final String CACHE_KEY_PREFIX_HOUSE_DETAIL = "cache:houseDetail:";
    //配置缓存key的失效时间
    public static final Integer CACHE_KEY_EXPIRE_TIME = 60*60*7;


    @Override
    public List<SpBuildingtype> getBuildingTypeByCellId(Long cellId) {
        Long tenantId =tenantTool.getTenantId();
        //1.先从redis查找数据，如果有直接返回
        List<SpBuildingtype> buildingTypeList= (List<SpBuildingtype>) redisTemplate.opsForValue().get(CACHE_KEY_PREFIX_TYPE+cellId);
        if(!ObjectUtil.isEmpty(buildingTypeList)){
            log.debug("缓存中查询到了对应的数据:{}",buildingTypeList);
            return buildingTypeList;
        }
        log.debug("缓存中没有查询到对应的数据，进行rpc的远程调用...");
        QueryWrapper query = QueryWrapper.create().from(SpBuildingtype.class)
                .eq(SpBuildingtype::getCellId, cellId)
                .eq(SpBuildingtype::getTenantId, tenantId);
                buildingTypeList = spBuildingtypeService.list(query);

        if(ObjectUtil.isEmpty(buildingTypeList)){
            log.error("没有查找到对应的数据:{}",buildingTypeList);
            throw new BusinessException(ResultEnum.NO_DATA,"没有查找到对应数据");
        }
        //3.写入数据到Redis
        redisTemplate.opsForValue().set(CACHE_KEY_PREFIX_TYPE + cellId,buildingTypeList);

        //4.设置失效时间
        redisTemplate.expire(CACHE_KEY_PREFIX_TYPE + cellId,CACHE_KEY_EXPIRE_TIME, TimeUnit.SECONDS);

        //5.返回数据
        return buildingTypeList;
    }

    @Override
    public List<SpBuilding> getBuildingByType(Long BuildingTypeId) {
        Long tenantId =tenantTool.getTenantId();
        //1.先从redis查找数据，如果有直接返回
        List<SpBuilding> buildingList= (List<SpBuilding>) redisTemplate.opsForValue().get(CACHE_KEY_PREFIX+BuildingTypeId);
        if(!ObjectUtil.isEmpty(buildingList)){
            log.debug("缓存中查询到了对应的数据:{}",buildingList);
            return buildingList;
        }
        log.debug("缓存中没有查询到对应的数据，进行rpc的远程调用...");
        QueryWrapper query = QueryWrapper.create().from(SpBuilding.class)
                .eq(SpBuilding::getBuildingtypeId, BuildingTypeId)
                .eq(SpBuilding::getTenantId, tenantId);
        buildingList = spBuildingService.list(query);

        if(ObjectUtil.isEmpty(buildingList)){
            log.error("没有查找到对应的数据:{}",buildingList);
            throw new BusinessException(ResultEnum.NO_DATA,"没有查找到对应数据");
        }
        //3.写入数据到Redis
        redisTemplate.opsForValue().set(CACHE_KEY_PREFIX + BuildingTypeId,buildingList);

        //4.设置失效时间
        redisTemplate.expire(CACHE_KEY_PREFIX + BuildingTypeId,CACHE_KEY_EXPIRE_TIME, TimeUnit.SECONDS);

        //5.返回数据
        return buildingList;
    }

    @Override
    public List<SpUnit> getUnitByBuilding(Long BuildingId) {
        //1.先从redis查找数据，如果有直接返回
        List<SpUnit> unitList= (List<SpUnit>) redisTemplate.opsForValue().get(CACHE_KEY_PREFIX_UNIT+BuildingId);
        if(!ObjectUtil.isEmpty(unitList)){
            log.debug("缓存中查询到了对应的数据:{}",unitList);
            return unitList;
        }
        log.debug("缓存中没有查询到对应的数据，进行rpc的远程调用...");
        QueryWrapper query = QueryWrapper.create().from(SpUnit.class)
                .eq(SpUnit::getBuildingId, BuildingId);
        unitList = spUnitService.list(query);

        if(ObjectUtil.isEmpty(unitList)){
            log.error("没有查找到对应的数据:{}",unitList);
            throw new BusinessException(ResultEnum.NO_DATA,"没有查找到对应数据");
        }
        //3.写入数据到Redis
        redisTemplate.opsForValue().set(CACHE_KEY_PREFIX_UNIT + BuildingId,unitList);

        //4.设置失效时间
        redisTemplate.expire(CACHE_KEY_PREFIX_UNIT + BuildingId,CACHE_KEY_EXPIRE_TIME, TimeUnit.SECONDS);

        //5.返回数据
        return unitList;
    }

    @Override
    public List<SpHouse> getHouseByUnitId(Long UnitId) {
        Long tenantId =tenantTool.getTenantId();
        //1.先从redis查找数据，如果有直接返回
        List<SpHouse> houseList= (List<SpHouse>) redisTemplate.opsForValue().get(CACHE_KEY_PREFIX_HOUSE+UnitId);
        if(!ObjectUtil.isEmpty(houseList)){
            log.debug("缓存中查询到了对应的数据:{}",houseList);
            return houseList;
        }
        log.debug("缓存中没有查询到对应的数据，进行rpc的远程调用...");
        QueryWrapper query = QueryWrapper.create().from(SpHouse.class)
                .eq(SpHouse::getUnitId, UnitId)
                .eq(SpHouse::getTenantId, tenantId);
        houseList = spHouseService.list(query);

        if(ObjectUtil.isEmpty(houseList)){
            log.error("没有查找到对应的数据:{}",houseList);
            throw new BusinessException(ResultEnum.NO_DATA,"没有查找到对应数据");
        }
        //3.写入数据到Redis
        redisTemplate.opsForValue().set(CACHE_KEY_PREFIX_HOUSE + UnitId,houseList);

        //4.设置失效时间
        redisTemplate.expire(CACHE_KEY_PREFIX_HOUSE + UnitId,CACHE_KEY_EXPIRE_TIME, TimeUnit.SECONDS);

        //5.返回数据
        return houseList;
    }

    @Override
    public void deleteBuildingTypeCache(Long cellId) {
        log.debug("删除建筑类型缓存数据:{}",cellId);
        redisTemplate.delete(CACHE_KEY_PREFIX_TYPE+cellId);
    }

    @Override
    public void deleteBuildingCache(Long BuildingTypeId) {
        log.debug("删除建筑缓存数据:{}",BuildingTypeId);
        redisTemplate.delete(CACHE_KEY_PREFIX+BuildingTypeId);

    }

    @Override
    public void deleteAllHouseCache() {
        //删除houseList所有缓存数据
        Set<String> keys = redisTemplate.keys(CACHE_KEY_PREFIX_HOUSE+"*");
        redisTemplate.delete(keys);
        log.debug("删除所有houseList缓存数据:{}",keys);
    }


    @Override
    public void deleteHouseCache(Long UnitId) {
        log.debug("删除单元缓存数据:{}",UnitId);
        redisTemplate.delete(CACHE_KEY_PREFIX_HOUSE+UnitId);

    }

    @Override
    public List<SpHouse> getHouseByOwnerId(Long ownerId) {
        try{
            //1.先从redis查找数据，如果有直接返回
            List<SpHouse> houseList= (List<SpHouse>) redisTemplate.opsForValue().get(CACHE_KEY_PREFIX_HOUSE+ownerId);
            if(!ObjectUtil.isEmpty(houseList)){
                log.debug("缓存中查询到了对应的数据:{}",houseList);
                return houseList;
            }else {
                log.debug("缓存中没有查询到对应的数据，进行rpc的远程调用...");
                houseList = spHouseService.myListByOwnerId(ownerId);
                if(ObjectUtil.isEmpty(houseList)){
                    log.error("没有查找到对应的数据:{}",houseList);
                    throw new BusinessException(ResultEnum.NO_DATA,"没有查找到对应数据");
                }else {
                    //3.写入数据到Redis
                    redisTemplate.opsForValue().set(CACHE_KEY_PREFIX_HOUSE + ownerId,houseList);
                    //4.设置失效时间
                    redisTemplate.expire(CACHE_KEY_PREFIX_HOUSE + ownerId,CACHE_KEY_EXPIRE_TIME, TimeUnit.SECONDS);
                    //5.返回数据
                    return houseList;
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public SpHouseVo getHouseById(Long houseId) {
        try{
            //1.先从redis查找数据，如果有直接返回
            SpHouseVo house = (SpHouseVo) redisTemplate.opsForValue().get(CACHE_KEY_PREFIX_HOUSE_DETAIL+houseId);
            if(!ObjectUtil.isEmpty(house)){
                log.debug("缓存中查询到了对应的数据:{}",house);
                return house;
            }else {
                log.debug("缓存中没有查询到对应的数据，进行rpc的远程调用...");
                house = spHouseService.queryHouseById(houseId);
                if(!ObjectUtil.isEmpty(house)){
                    //3.写入数据到Redis
                    redisTemplate.opsForValue().set(CACHE_KEY_PREFIX_HOUSE_DETAIL + houseId,house);
                    //4.设置失效时间
                    redisTemplate.expire(CACHE_KEY_PREFIX_HOUSE_DETAIL + houseId,CACHE_KEY_EXPIRE_TIME, TimeUnit.SECONDS);
                    //5.返回数据
                    return house;
                }else throw new BusinessException(ResultEnum.NO_DATA,"没有查找到对应数据");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    @DubboReference
    private SpHouseRentalService spHouseRentalService;
    @Override
    public boolean rentHouse(SpHouseRentalAddDto spHouseRentalAddDto) {
        try{
//            //远程调用获取真实业主id
//            Long ownerId = spHouseService.getOwnerId(spHouseRentalAddDto.getOwnerId());
//            spHouseRentalAddDto.setOwnerId(ownerId);
            return spHouseRentalService.mySave(spHouseRentalAddDto);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public SpHouseRental chackHouseIsRent(Long houseId) {
        return spHouseRentalService.myGetById(houseId);
    }

    @Override
    public List<SpHouseRentalListVo> listSpHouseRentals(SpHouseRentalQueryDto spHouseRentalQueryDto) {
        return spHouseRentalService.listSpHouseRentals(spHouseRentalQueryDto);
    }
}
